<template>
  <div class="content-container-left" :style="{ width: getListWidth() }">
    <div class="title">{{ props.title }}列表</div>
    <div v-if="props.selectApi" class="select-filter">
      <el-select
        v-model="queryParams[props.selectProp]"
        filterable
        placeholder=""
        :loading="selectLoading"
        :loading-text="`正在加载${props.selectPlaceholder}数据`"
        @change="handleQuery"
      >
        <el-option
          v-for="item in dataInfo.selectData"
          :key="item[props.selectValueProp]"
          :label="item[props.selectLabelProp]"
          :value="item[props.selectValueProp]"
        />
        <template #empty>
          {{ `暂无${ props.selectPlaceholder }数据` }}
        </template>
      </el-select>
      <div v-if="selectLoading" class="select-loading">
        <i class="el-icon-loading" style="margin-right: 0.5rem" />
        <div style="line-height: 2rem;font-size: inherit">{{ `正在加载${ props.selectPlaceholder }数据` }}</div>
      </div>
    </div>
    <div v-if="props.showQuery" class="filter" style="user-select: none;">
      <el-input
        v-model="queryParams.keywords"
        class="input"
        clearable
        placeholder="输入关键词搜索"
        @change="handleQuery"
      />
      <el-button type="primary" style="margin-left: 14px;" @click="handleQuery">搜索</el-button>
    </div>
    <div class="select-list">
      <el-scrollbar ref="scrollbarRef" style="height: 100%;">
        <div
          v-infinite-scroll="loadMoreData"
          :infinite-scroll-immediate="false"
          :infinite-scroll-delay="443"
          :infinite-scroll-disabled="dataInfo.noMore || dataInfo.loading || dataInfo.tableData.length < 0"
        >
          <div v-if="dataInfo.tableData.length">
            <div
              v-if="props.showAll"
              class="select-list-item"
              :style="{ width: `calc(${getListWidth()} - 2.5rem)` }"
              :class="{
                active: (!dataInfo.cur || !dataInfo.cur.id) && !hasSecond,
                secondActive: (!dataInfo.cur || !dataInfo.cur.id) && hasSecond
              }"
              @click="handleRowClick({ id: '' })"
            >
              <svg-icon v-if="props.icon" :icon-class="props.icon" class-name="icon" />
              <span>全部</span>
            </div>
            <div
              v-for="(item, index) in dataInfo.tableData"
              :key="item.id"
              class="select-list-item"
              :style="{ width: `calc(${getListWidth()} - 2.5rem)` }"
              :class="{
                active: !hasSecond ? dataInfo.cur && item.id === dataInfo.cur.id : false,
                'select-list-item-open': hasSecond && index === curData.index && curData.open,
              }"
              @click="handleRowClick(item, index)"
            >
              <svg-icon
                v-if="props.icon"
                :style="{ color: hasSecond && item.secondData?.find(v => v.id === dataInfo?.cur?.id) ? '#1990ff' : null }"
                style="transition: color 0.3s ease;"
                :icon-class="props.icon"
                class-name="icon"
              />
              <span
                style="transition: color 0.3s ease;"
                :style="{ color: hasSecond && item.secondData?.find(v => v.id === dataInfo?.cur?.id) ? '#1990ff' : null }"
              >{{
                item[props.itemProp] }}</span>
              <div v-if="hasSecond" class="select-list-item-icon_box">
                <div
                  v-loading="item.loading"
                  element-loading-spinner="el-icon-loading"
                  element-loading-background="rgba(0, 0, 0, 0)"
                  class="select-list-item-icon_box-loading"
                />
                <i
                  v-show="!item.loading"
                  :class="hasSecond && index === curData.index && curData.open ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
                  class="select-list-item-icon_box-icon"
                />
              </div>
              <div
                v-if="hasSecond"
                class="select-list-item-down"
                :style="{ height: hasSecond && index === curData.index && curData.open ? item.secondData.length > 1 ? item.secondData.length * 2.42 + 'rem' : 2.42 + 'rem' : '0' }"
              >
                <div
                  v-for="(second, secondIndex) in item.secondData"
                  v-show="hasSecond && item.secondData?.length && index === curData.index && curData.open"
                  :key="second.id"
                  class="select-list-item-dropdown select-list-item-dropdown-notEmpty"
                  :class="{ active: hasSecond ? dataInfo.cur && second.id === dataInfo.cur.id : false, 'dropdown-first-top': secondIndex === 0 }"
                  @click.stop="handleLoadRightData(second, item)"
                >
                  -&nbsp;&nbsp;&nbsp;&nbsp;<span>{{ second[props.itemSecondProp] }}</span>
                </div>
                <div
                  v-if="hasSecond && index === curData.index && curData.open"
                  v-show="item.secondData.length === 0"
                  class="select-list-item-dropdown select-list-item-dropdown-empty"
                >
                  <span>暂无数据</span>
                </div>
              </div>
            </div>
            <p v-if="dataInfo.loading" class="loading el-icon-loading" />
            <p v-if="dataInfo.noMore && dataInfo.tableData.length > 20" class="noMore">没有更多了</p>
          </div>
        </div>
      </el-scrollbar>
      <div v-if="dataInfo.tableData.length === 0" class="nodata">
        <p v-if="dataInfo.loading" class="loading el-icon-loading" style="color: #1c84c6" />
        <div v-else>暂无{{ props.title }}</div>
      </div>
    </div>
    <div class="resize" @mousedown.left="startDrag" />
  </div>
</template>

<script setup>
import leftListProp from './leftListProp.js'

defineOptions({
  name: 'LeftList'
})

const props = defineProps({...leftListProp})

const emits = defineEmits(['change'])

const loadNewRightData = inject('loadNewRightData')
const loadNoData = inject('loadNoData')

const scrollbarRef = ref(null)
const listWidth = ref(null)
const maxListWidth = ref(null)
const minListWidth = ref(null)
const selectLoading = ref(true)
const dragging = ref(false)

// 加载左侧数据条件
const queryParams = ref({
  pageIndex: 1,
  pageSize: 10,
  keywords: '',
  chooseIds: ''
})

// 保存当前点击左侧数据索引是否展开
const curData = ref({
  index: null,
  open: false
})

// 左栏数据
const dataInfo = ref({
  loading: false, // 是否正在加载
  tableData: [], // 表格数据
  selectData: [], // 选择器数据
  cur: undefined, //  当前选中行对象
  noMore: false //  是否没有更多数据
})

// 左边栏是否有二级
const hasSecond = computed(() => props.listSecondApi.length > 0)

// 监听搜索条件变化
watch(() => props.searchProps, (newVal) => {
  newVal.forEach(item => {
    queryParams.value[item.prop] = item.default
    if (item.prop === 'chooseIds' && dataInfo.value?.tableData) {
      const Data = dataInfo.value.tableData.find(v => v.id === queryParams.value.chooseIds)
      Data && handleRowClick(Data)
    }
  })
}, {immediate: true})

// 工具方法
const isNotNaN = (value) => {
  return !(value === undefined || value === null || value === '')
}

// 拖拽相关方法
const startDrag = (event) => {
  if (event.button === 0) {
    dragging.value = true
    document.addEventListener('mousemove', onDragging)
    document.addEventListener('mouseup', endDrag)
  }
}

const onDragging = (event) => {
  if (dragging.value) {
    const width = listWidth.value + event.movementX
    width > maxListWidth.value ? listWidth.value = maxListWidth.value :
        width < minListWidth.value ? listWidth.value = minListWidth.value :
            listWidth.value = width
  }
}

const endDrag = () => {
  dragging.value = false
  document.removeEventListener('mousemove', onDragging)
  document.removeEventListener('mouseup', endDrag)
}

// 获取列表宽度
const getListWidth = () => {
  if (listWidth.value) return listWidth.value + 'px'
  return typeof props.width === 'number' ? props.width + 'rem' : props.width
}

// 获取选择器数据
const getSelectData = () => {
  if (props.selectData.length > 0) {
    dataInfo.value.selectData = props.selectData
    queryParams.value[props.selectProp] = props.selectData[0][props.selectValueProp]
  } else if (props.selectApi) {
    selectLoading.value = true
    const http = $xl.apis[props.selectApi]
    if (!http) return $xl.modal.msgError('未找到选择器接口')
    http().then(res => {
      selectLoading.value = false
      dataInfo.value.selectData = res.data
      const isNaN = !isNotNaN(queryParams.value[props.selectProp])
      if (isNaN) queryParams.value[props.selectProp] = res.data[0][props.selectValueProp]
      getList()
    }).catch(err => {
      $xl.modal.msgError(err)
    }).finally(() => selectLoading.value = false)
  } else {
    getList()
  }
}

// 获取列表数据入口
const getList = () => {
  if (props.listData.length > 0) {
    dataInfo.value.noMore = true
    handleListData(props.listData)
  } else if (props.listApi) {
    fetchListData()
  } else {
    $xl.modal.msgError('未配置左侧列表数据或者接口')
  }
}

// 处理列表数据
const handleListData = (data) => {
  data.forEach(item => {
    item.loading = false
    dataInfo.value.tableData.push(item)
  })

  if (dataInfo.value.tableData.length && !dataInfo.value.cur) {
    if (props.showAll && !queryParams.value.chooseIds) {
      handleRowClick({id: ''})
    } else {
      const selectedRow = queryParams.value.chooseIds ?
          dataInfo.value.tableData.find(v => v.id === queryParams.value.chooseIds) || dataInfo.value.tableData[0] :
          dataInfo.value.tableData[0]
      handleRowClick(selectedRow, 0, 'isInit')
    }
  } else {
    loadNoData(props.toRightRequestName)
  }

  scrollbarRef.value?.update()
}

// 请求列表数据
const fetchListData = () => {
  dataInfo.value.loading = true
  const http = $xl.apis[props.listApi]
  if (!http) return $xl.modal.msgError('未找到列表接口')
  http({
    params: queryParams.value
  }).then(res => {
    if (res.data.records) {
      handleListData(res.data.records)
      if (res.data.current >= res.data.pages && res.data.records.length <= queryParams.value.pageSize) {
        dataInfo.value.noMore = true
      }
    } else {
      handleListData(res.data)
      dataInfo.value.noMore = true
    }
  }).catch(err => {
    dataInfo.value.noMore = true
    dataInfo.value.tableData = []
    $xl.modal.msgError(err)
  }).finally(() => {
    dataInfo.value.loading = false
  })
}

// 触发左栏查询
const handleQuery = () => {
  dataInfo.value.tableData = []
  dataInfo.value.cur = undefined
  dataInfo.value.noMore = false
  curData.value = {index: null, open: false}
  queryParams.value.pageIndex = 1
  getList()
}

// 触发左栏加载更多
const loadMoreData = () => {
  dataInfo.value.tableData.length > 0 &&
  !dataInfo.value.noMore &&
  !dataInfo.value.loading &&
  queryParams.value.pageIndex++ &&
  getList()
}

// 点击左栏项，触发右边栏数据加载
const handleRowClick = (row, index = undefined, isInit = undefined) => {
  if (hasSecond.value && index >= 0) {
    if (dataInfo.value.tableData[index].secondData) {
      handleLeftItemOpen(index)
    } else {
      dataInfo.value.tableData[index].loading = true
      $xl.apis[props.listSecondApi]({
        params: {id: dataInfo.value.tableData[index].id}
      }).then(res => {
        if (res.data && !Array.isArray(res.data)) return $xl.modal.msgError('二级菜单数据格式错误')
        dataInfo.value.tableData[index].secondData = res.data
        handleLeftItemOpen(index, isInit)
      }).finally(() => {
        dataInfo.value.tableData[index].loading = false
      })
    }
  } else {
    curData.value.index = -1
    curData.value.open = false
    handleLoadRightData(row)
  }
}

// 点击左栏项，当前项展开或关闭,其他项关闭
const handleLeftItemOpen = (index, isInit) => {
  if (curData.value.index === index) {
    curData.value.open = !curData.value.open
  } else {
    curData.value.index = index
    curData.value.open = true
    if (isInit) {
      const selectedRow = dataInfo.value.tableData[index].secondData[0] || null
      handleLoadRightData(selectedRow)
    }
  }
}

// 右边栏数据加载
const handleLoadRightData = (row, parent) => {
  if (row === null && hasSecond.value) return loadNoData(props.toRightRequestName)
  if (dataInfo.value.cur?.id === row?.id) return
  dataInfo.value.cur = row
  emits('change', row)
  loadNewRightData(row, props.toRightRequestName, props.toRightRequestValue)
}

onMounted(() => {
  const rootFontSize = Number(document.documentElement.style.fontSize.replace('px', ''))
  minListWidth.value = 10 * rootFontSize
  maxListWidth.value = 37 * rootFontSize

  getSelectData()
  window.addEventListener('resize', () => scrollbarRef.value?.update())
  listWidth.value = document.querySelector('.content-container-left')?.clientWidth
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', () => scrollbarRef.value?.update())
})
</script>

<style scoped lang="scss">
.content-container-left {
  background: #ffffff;
  border-radius: 5px;
  padding: 20px;
  margin-right: 20px;
  display: flex;
  flex-direction: column;
  position: relative;

  .resize {
    position: absolute;
    right: 0;
    bottom: 0.5%;
    width: 3px;
    height: 99%;
    cursor: ew-resize;
    /* 鼠标样式 */
  }

  .title {
    font-size: 22px;
    color: #73767a;
    font-weight: 700;
    margin-bottom: 27px;
    text-wrap: nowrap;
  }

  .select-filter {
    margin-bottom: 10px;
    position: relative;

    .select-loading {
      height: 100%;
      left: 0.6rem;
      top: 0;
      position: absolute;
      display: flex;
      align-items: baseline;
      color: #1c84c6;
    }
  }

  .filter {
    display: flex;
    align-items: center;
  }

  .select-list {
    margin-top: 30px;
    flex: 1;
    overflow: auto;
    position: relative;

    .nodata {
      position: absolute;
      top: 25%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #b1b1b1;
    }

    .loading {
      display: flex;
      align-items: center;
      justify-content: center;
      color: #aaa;
    }

    .noMore {
      display: flex;
      align-items: center;
      justify-content: center;
      color: #aaa;
      margin-top: 60px;
      font-size: 14px;
    }

    :deep(.el-scrollbar__wrap) {
      overflow-x: hidden;
    }

    &-item {
      padding: 10px 16px;
      margin-bottom: 10px;
      font-size: 15px;
      color: #606266;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
      cursor: pointer;
      border-radius: 10px;
      box-sizing: border-box;
      user-select: none;
      transition: all 0.3s;

      .icon {
        margin-right: 10px;
        font-size: 16px;
      }

      &-icon_box {
        display: flex;
        position: relative;
        font-size: 12px;

        &-loading {
          position: absolute;
          right: 16px;
          top: 0;

          :deep(.el-loading-spinner) {
            font-size: 20px;
          }
        }

        &-icon {
          position: absolute;
          right: 0;
          top: -18px;
        }
      }

      &-open {
        background-color: #fafafa;

        //&:before {
        //  width: 97% !important;
        //}
      }

      &-dropdown {
        display: flex;
        padding: 10px 20px;
        transition: color 0.5s ease;

        &.dropdown-first-top {
          margin-top: 10px;
        }

        &-empty {
          margin-left: 0;
          color: #888;
          display: flex;
          justify-content: center;
          margin-top: 10px;
        }

        &-notEmpty:hover {
          color: #1990ff;
        }

        &-tree {
          font-size: 25px;
          margin-right: 5px;
        }

        &.active {
          color: #1990ff;
        }
      }

      &-down {
        transition: all 0.3s;
      }

      &.active {
        background-color: #f5f7fa;
        color: #1990ff;
      }

      &.secondActive {
        color: #1990ff;
      }

      &:hover {
        background-color: #f5f7fa;
      }

      //&:before {
      //  transition: all 0.3s;
      //  content: "";
      //  display: block;
      //  position: relative;
      //  top: 2rem;
      //  right: 1rem;
      //  width: 0;
      //  height: 1px;
      //  background-color: #606266;
      //}
    }

  }
}
</style>
